<?php
namespace app\serverfund\logic;

use \app\manage\logic\BaseLogic;
/*使用支付宝类*/
use alipay\ClientResponseHandler;
use alipay\PayHttpClient;
use alipay\RequestHandler;
use alipay\Utils;

/**
 * @author:      李颖
 * @DateTime:    2017-09-08 10:25:59
 * @Description: 原始支付宝代码   来源：测试案例中的request.php文件修改而来
 */
class RequestAlipay extends BaseLogic
{

    protected $config = 'db_config_fund';
    protected $name = 'pay_log';
    private $resHandler = null;
	private $resHandler2 = null;
    private $reqHandler = null;
    private $pay = null;
    private $cfg = null;

    public function __construct(){
        $this->Request();
    }

    public function Request(){
        $this->resHandler = new ClientResponseHandler();
        $this->resHandler2 = new ClientResponseHandler();
        $this->reqHandler = new RequestHandler();
        $this->pay = new PayHttpClient();
        $this->cfg = config('weiFortisPay');

        $this->reqHandler->setGateUrl($this->cfg['url']);  //读取配置
        $this->reqHandler->setKey($this->cfg['key']);
    }


    /**
     * 提交订单信息  
     */
    public function submitOrderInfo($paramData){
        $nonce_str = mt_rand(NOW, NOW + rand());
        $this->reqHandler->setReqParams($paramData);
        // 设置参数
        $this->reqHandler->setParameter('service', 'pay.alipay.native');//接口类型
        $this->reqHandler->setParameter('mch_id', $this->cfg['mchId']);//必填项，商户号，由平台分配
        $this->reqHandler->setParameter('notify_url', $this->cfg['notify_url']);
	    $this->reqHandler->setParameter('version', $this->cfg['version']);
        $this->reqHandler->setParameter('nonce_str', $nonce_str);//随机字符串，必填项，不长于 32 位
        $this->reqHandler->createSign();//创建签名
        $data = Utils::toXml($this->reqHandler->getAllParameters());

        $this->pay->setReqContent($this->reqHandler->getGateURL(), $data);
        if(!$this->pay->call()){
            $payRes = [
                'status' => 500,
                'msg' => 'Response Code:' . $this->pay->getResponseCode()
                    .' Error Info:' . $this->pay->getErrInfo()
            ];
            return auto_failure($payRes, $this->pay->getErrInfo());
        }
        // 设置要发送的内容
        $this->resHandler->setContent($this->pay->getResContent());
        $this->resHandler->setKey($this->reqHandler->getKey());
        // 如果签名验证通过
        if(!$this->resHandler->isTenpaySign()){
            $payRes = [
                'status'=>500,
                'msg'=>'Error Code1:' . $this->resHandler->getParameter('status')
                        . ' Error Message:' . $this->resHandler->getParameter('message')
            ];
            return auto_failure($payRes, $this->resHandler->getParameter('message'));
        }
        if($this->resHandler->getParameter('status') != 0 || $this->resHandler->getParameter('result_code') != 0){
            $payRes = [
                'status' => 500,
                'msg' => 'Error Code2:' . $this->resHandler->getParameter('err_code')
                        . ' Error Message:' . $this->resHandler->getParameter('err_msg')
            ];
            return auto_failure($payRes, $this->resHandler->getParameter('err_msg'));
        }
        $payRes = [
            'code_img_url' => $this->resHandler->getParameter('code_img_url'),
            'code_url' => $this->resHandler->getParameter('code_url'),
            'sign' => $this->resHandler->getParameter('sign'),
            'nonce_str' => $this->resHandler->getParameter('nonce_str')
        ];
        //此方法为中间调用方法，不直接返回,在此可返回sign nonce_str
        return auto_success($payRes);
    }

    /**
     * 异步通知回调方法
     */
    public function receivePayNotify($xml){

        $arr = xml_to_array($xml);
        $addLog['xml'] = $arr;
        $callBackLogic = logic('app\serverfund\logic\CallbackLog');
        
        /*正确代码：*/
        /*正确代码开始*/
        //添加回调日志记录
        $this->resHandler->setContent($xml);
        $this->resHandler->setKey($this->cfg['key']);
        //签名验证不通过添加记录
        $addLog['out_trade_no'] = $arr['out_trade_no'];
        $addLog['sign'] = $arr['sign'];
        if(!$this->resHandler->isTenpaySign()){
            $addLog['remark'] = '错误：数字签名验证不通过';
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'success';
        }
        /*$arr = [
            'attach' => '亚数平台充值',
            'bank_type' => 'PCREDIT',
            'buyer_logon_id' => '139****0570',
            'buyer_user_id' => '2088502589814873',
            'charset' => 'UTF-8',
            'fee_type' => 'CNY',
            'mch_id' => '102530433562',
            'nonce_str' => '2373177612',
            'openid' => '2088502589814873',
            'out_trade_no' => 5,
            'out_transaction_id' => '2017091821001004870501086273',
            'pay_result' => 0,
            'result_code' => 0,
            'sign' => '1A082455D309054E03E3E39AF4B8268D',
            'sign_type' => 'MD5',
            'status' => 0,
            'time_end' => '20170919113711',
            'total_fee' => 1,
            'trade_type' => 'pay.alipay.native',
            'transaction_id' => '102530433562201709183181415034',
            'version' => 2.0
        ];
        $callBackLogic = logic('app\serverfund\logic\CallbackLog');
        $addLog['xml'] = $arr;*/
        //调用的重复检查  +1
        $payLogModel = $this->model('\app\serverfund\model\PayLog');
        $findPayLogWhere['id'] = $arr['out_trade_no'];
        $payLogInfo = $payLogModel->where($findPayLogWhere)->find();
        if($payLogInfo['callback_count'] > 0){
            $addLog['remark'] = '错误：重复调用异步通知回调方法';
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            $payLogModel->where($findPayLogWhere)->setInc('callback_count');
            return 'success';
        }
        $payLogModel->where($findPayLogWhere)->setInc('callback_count');
        
        //调用接口查询到的订单信息
        $queryOrderRes = $this->queryOrder(['out_trade_no'=>$arr['out_trade_no']]);//查询订单是否支付  查询远程订单
        if($queryOrderRes['status'] != SUCCESS_STATUS){
            $addLog['remark'] = '查询订单错误：' . $queryOrderRes['msg'];
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'success';
        }
        if($queryOrderRes['res']['status'] != 0 || $queryOrderRes['res']['result_code'] != 0){
            $addLog['remark'] = '错误：支付失败';
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'success';
        }
        $trueArr = $queryOrderRes['res'];

        //检查一下是否已执行过
        $checkWhere['id'] = $trueArr['out_trade_no'];
        $checkWhere['status'] = 1;
        $checkInfo = $payLogModel->where($checkWhere)->find();
        if($checkInfo){
            $addLog['remark'] = '错误：已执行过该操作，不可重复执行';
            $addLog['status'] = 0;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'success';
        }

        //1、检查支付记录
        $_getLogWhere['id'] = $trueArr['out_trade_no'];
        $payLogInfo = $payLogModel->where($_getLogWhere)->find();
        if(!$payLogInfo){ 
            $this->_callRechargeFailure($trueArr, $_getLogWhere, '未找到相应的支付记录');
            return 'success';
        }
        //向下多用trueArr
        $savePayLog['return_param'] = $trueArr;
        $savePayLog['return_status'] = $trueArr['status'];
        $savePayLog['return_result_code'] = $trueArr['result_code'];
        //支付成功后。。。
        $this->db()->startTrans();
        try{
            //2、执行系统充值方法
            $rechargeData['user_id'] = $payLogInfo['user_id'];
            $rechargeData['app_id'] = $payLogInfo['app_id'];
            $rechargeData['update_ip'] = request()->ip();
            $rechargeData['user_info'] = '{}';
            $rechargeData['opposite_info'] = '{}';

            if($payLogInfo['recharge_type'] == 'cash'){
                $rechargeData['money'] = $payLogInfo['money'];
                $rechargeRes = logic('app\serverfund\logic\FundAccount')->prepaid($rechargeData);
            }elseif($payLogInfo['recharge_type'] == 'currency'){
                $rechargeData['currency'] = $payLogInfo['receive_param']['recharge_currency'];
                $rechargeRes = logic('app\serverfund\logic\CurrencyAccount')->prepaid($rechargeData);
            }else{
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '该条记录充值类型错误');
                return 'success';
            }
            if($rechargeRes['status'] != SUCCESS_STATUS){
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '系统充值失败');
                return 'success';
            }
            //3、更新pay_log记录表 
            $savePayLog['option_log_id'] = $rechargeRes['res']['autoRes'];
            $savePayLog['status'] = 1;
            $savePayLog['result_status'] = 1;
            $savePayLogRes = $payLogModel->save($savePayLog, $_getLogWhere);
            if(!$savePayLogRes){
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '更新支付记录表失败');
                return 'success';
            }
            //添加回调记录
            $addLog['remark'] = '充值成功';
            $addLog['status'] = 1;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            if(!$addCallbackLog){
                $this->db()->rollback();
                $this->_callRechargeFailure($trueArr, $_getLogWhere, '添加回调记录失败');
                return 'success';
            }
            // 提交事务
            $this->db()->commit();
            return 'success';

        } catch (\Exception $e) {// 回滚事务
            $this->db()->rollback();
            $saveErroPayLog['status'] = 1;
            $saveErroPayLog['result_status'] = 2;
            $saveErroPayLogRes = $payLogModel->save($saveErroPayLog, $_getLogWhere);
            //添加记录
            $addLog['remark'] = '支付成功，充值失败！错误原因：' . $e->getMessage();
            $addLog['status'] = 2;
            $addCallbackLog = $callBackLogic->addLog($addLog);
            return 'success';
        }

    }

    /*支付成功，充值失败
    1、添加回调记录
    2、修改支付记录状态*/
    public function _callRechargeFailure($xmlArray, $findPayLogWhere, $erroMsg)
    {
        $payLogModel = $this->model('\app\serverfund\model\PayLog');
        $callBackLogic = logic('app\serverfund\logic\CallbackLog');

        $saveErroPayLog['return_param'] = $xmlArray;
        $saveErroPayLog['return_status'] = $xmlArray['status'];
        $saveErroPayLog['return_result_code'] = $xmlArray['result_code'];
        $saveErroPayLog['status'] = 1;
        $saveErroPayLog['result_status'] = 2;
        $saveErroPayLogRes = $payLogModel->save($saveErroPayLog, $findPayLogWhere);
        //添加记录
        $addLog['xml'] = $xmlArray;
        $addLog['remark'] = '支付成功，充值失败!错误原因：' . $erroMsg;
        $addLog['status'] = 2;
        $addCallbackLog = $callBackLogic->addLog($addLog);
    }

    /*根据订单号查询订单 $queryData['out_trade_no'] = 6;*/
    public function queryOrder($queryData){
        $this->reqHandler->setReqParams($queryData);
        $reqParam = $this->reqHandler->getAllParameters();
        if(empty($reqParam['transaction_id']) && empty($reqParam['out_trade_no'])){
            return auto_failure(null, '请输入商户订单号或平台订单号!');
        }
        $this->reqHandler->setParameter('version',$this->cfg['version']);
        $this->reqHandler->setParameter('service','unified.trade.query');//接口类型
        $this->reqHandler->setParameter('mch_id',$this->cfg['mchId']);//必填项，商户号，由平台分配
        $this->reqHandler->setParameter('nonce_str',mt_rand(time(),time()+rand()));//随机字符串，必填项，不长于 32 位
        $this->reqHandler->createSign();//创建签名
        $data = Utils::toXml($this->reqHandler->getAllParameters());

        $this->pay->setReqContent($this->reqHandler->getGateURL(),$data);
        if(!$this->pay->call()){
            return auto_failure(null, 'Response Code:' . $this->pay->getResponseCode() . ' Error Info:' . $this->pay->getErrInfo());
        }
        $this->resHandler2->setContent($this->pay->getResContent());
        $this->resHandler2->setKey($this->reqHandler->getKey());
        if(!$this->resHandler2->isTenpaySign()){
            return auto_failure(null, 'Error Code:' . $this->resHandler2->getParameter('status') . ' Error Message:' . $this->resHandler2->getParameter('message'));
        }
        $res = $this->resHandler2->getAllParameters();
        return auto_success($res);
    }

}
